package com.zhhtech.zhh.ui.interceptor

import androidx.collection.arraySetOf
import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONObject
import com.zhhtech.zhh.api.core.ResultBean
import com.zhhtech.zhh.common.ACTION_REQUEST
import com.zhhtech.zhh.common.UserCache
import com.zhhtech.zhh.ui.AppCore
import com.zhhtech.zhh.ui.helper.getImei
import com.zhhtech.zhh.ui.helper.localSendBroadcastSync
import okhttp3.Interceptor
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.Response
import okhttp3.ResponseBody.Companion.toResponseBody
import retrofit2.Invocation
import java.lang.reflect.Method


/**
 * 取消拦截处理
 */
@Target(
    AnnotationTarget.FUNCTION,
    AnnotationTarget.PROPERTY_GETTER,
    AnnotationTarget.PROPERTY_SETTER
)
@Retention(AnnotationRetention.RUNTIME)
annotation class CancelConvert

/**
 * 响应结果除了code、data、msg之外全部的参数全部组装放到data里面
 */
@Target(
    AnnotationTarget.FUNCTION,
    AnnotationTarget.PROPERTY_GETTER,
    AnnotationTarget.PROPERTY_SETTER
)
@Retention(AnnotationRetention.RUNTIME)
annotation class ResponseToData


class ConvertInterceptor : Interceptor {
    companion object {
        private val DEFAULT_RESULT =
            """{"msg":"未知错误","code":${ResultBean.SERVICE_ERROR}}""".trimIndent()
        val CONTENT_TYPE = "application/json;charset=utf-8".toMediaType()
        private const val MEDIA_TYPE_SUB = "json"
        private val KEYS = arrayOf("code", "data", "msg")

        fun handleResponse(response: Response, method: Method?): Response {
            val responseToData: Boolean =
                (method?.getAnnotation(ResponseToData::class.java) != null)
            if (response.isSuccessful) {
                if (MEDIA_TYPE_SUB == response.body?.contentType()?.subtype) {
                    val bodyStr = response.body?.string()
                    var body = try {
                        // 不是json格式
                        if (bodyStr?.startsWith("{") == false && !bodyStr.startsWith("[")) {
                            DEFAULT_RESULT
                            // 返回内容包含null，排除一下null
                        } else if (bodyStr?.indexOf("null") != -1) {
                            JSON.toJSONString(JSON.parseObject(bodyStr))
                        } else {
                            bodyStr
                        }
                    } catch (e: Exception) {
                        DEFAULT_RESULT
                    }
                    if (responseToData) {
                        val bodyJson = JSON.parseObject(bodyStr)
                        val newDataJson = JSONObject()
                        newDataJson.putAll(bodyJson)
                        KEYS.forEach { key ->
                            newDataJson.remove(key)
                        }
                        arraySetOf<String>().apply {
                            addAll(bodyJson.keys)
                        }.forEach { key ->
                            if (!KEYS.contains(key)) {
                                bodyJson.remove(key)
                            }
                        }
                        bodyJson["data"] = newDataJson
                        body = bodyJson.toJSONString()
                    }
                    return response.newBuilder().body(body.toResponseBody(CONTENT_TYPE)).build()
                }
                localSendBroadcastSync(AppCore.app, ACTION_REQUEST)
            }
            return response
        }
    }

    override fun intercept(chain: Interceptor.Chain): Response {
        var request = chain.request()
        val method: Method? = request.tag(Invocation::class.java)?.method()
        request = request.newBuilder()
            .apply {
                url(
                    request.url.newBuilder()
                        .addEncodedQueryParameter("channel", com.zhhtech.zhh.App.channel)
                        .addEncodedQueryParameter("imei", getImei())
                        .build()
                )
                UserCache.getToken().takeIf { it.isNotEmpty() }?.let {
                    header("token", it)
                }
            }
            .build()
        return handleResponse(chain.proceed(request), method)
    }
}